// 要弄清import * as protobuf from 'protobufjs'; 与 import protobuf from 'protobufjs'; 关系有几个要点

// 1.ES module 和 CommonJS 是两种不同的模块系统，它们有一些区别如下：
// 语法： ES module 使用 import 和 export 关键字来导入和导出模块，而 CommonJS 使用 require 和 module.exports 来导入和导出模块。
// 动态导入：ES module 支持动态导入，也就是在代码运行时根据需要导入模块。而 CommonJS 不支持动态导入。
// 作用域： ES module 的模块作用域是静态的，在模块中定义的变量和函数不会污染全局作用域。而 CommonJS 的模块作用域是动态的，模块中定义的变量和函数会被添加到全局作用域中。
// 异步加载：ES module 可以异步加载模块，以提高性能和减少启动时间。而 CommonJS 只能同步加载模块。
// 循环依赖：ES module 可以处理循环依赖，因为它使用静态作用域。而 CommonJS 可能会因为循环依赖导致程序崩溃。
// 浏览器兼容性：ES module 在现代浏览器中得到广泛支持，但在旧版浏览器中无法使用。而 CommonJS 可以在所有现代浏览器和 Node.js 中使用。
// 总的来说，ES module 更加现代化和灵活，支持动态导入、异步加载、静态作用域等特性，而 CommonJS 更加简单和适用于早期的 Node.js 环境。在实际开发中，需要根据具体的项目需求和环境来选择使用哪种模块系统。

// 2.早期的npm包都是commonjs模块，如何查看protobufjs是什么模块： 通常通过包中的package.json文件的"type"字段来指定其默认的模块类型。如果该字段的值为"module"，则表示默认为ES模块；如果不指定或为其他值，则默认为CommonJS。
// protobufjs没有moude字段所以是commonjs模块。。也可以查看代码或者官网文档 ：All variants support CommonJS and AMD loaders and export globally as window.protobuf.

// 3.cocos中tsconfig.json配置中 "module": "ES2015", 说明是es模块，无法直接引用protobufjs..直接使用 import * as protobuf from 'protobufjs是可以的，但这时候protobuf不是对象而是moduel。 import protobuf from 'protobufjs 会报错需要tscongfic.json 添加
// {
// "allowSyntheticDefaultImports": true,
// }
// allowSyntheticDefaultImports是TypeScript编译器中的一个编译选项，它的作用主要是为了提升与老的JavaScript模块系统（如CommonJS）以及一些非标准模块导出方式的兼容性。具体来说，这个设置允许TypeScript按照ES模块的默认导入风格来处理那些没有明确标记为默认导出的模块。
//导入命名空间
import protobuf  from "protobufjs"

export interface Codec<T>{
    encode(msg:T,writer?:protobuf.Writer):Uint8Array

    decode(reader:any,length?:number):T;
}

export class ProtobufProxy{

    public static codecMap:Map<String,Codec<any>>  = new Map()


    static create<T>( type:new (...args: any[]) => T):Codec<T>{
            //构造字符串，eval执行
        let template = `


        `
        //检查缓存
        let codec = this.codecMap.get(type.name)
        if(codec){
            return codec
        }
        codec = {} as Codec<any>
        codec.encode = ProtobufProxy.encodeDo
        codec.decode = ProtobufProxy.decodeDo
        this.codecMap.set(type.name,codec)
        return codec   
    }

    static encode(msg: any,writer?:protobuf.Writer): Uint8Array {
        let obj = Object.getPrototypeOf(msg)
        let typeName = obj.constructor.name
        let codec = this.codecMap.get(typeName)
        if(!codec){
            console.error("未注册的消息处理器名："+typeName);
            return null
        }
        return codec.encode(msg)
    }
    //泛型？
    static decode(msg:any,length?:number): any {
        let typeName = typeof(msg)
        let codec = this.codecMap.get(typeName)
        if(!codec){
            console.error("未注册的消息处理器名："+typeName);
            return null
        }
        return codec.decode(msg)
    }
    private static decodeDo(reader:any,length?:number): any {

    }
    private static encodeDo(msg: any,writer?:protobuf.Writer): Uint8Array {
        if(!writer){
            writer = protobuf.Writer.create()
        }
        //===================属性序列化_Start=======================
        //基本类型 number string 
        //复杂类型 [] map set
        //自定义类型
        let keys = Object.keys(msg)
        let len = keys.length
        for(let index = 0;index<len;index++){
            let key = keys[index]
            let value = msg[key]
            if(!value){
                continue
            }
            //记录字段的顺序？
            //基本类型
            if(typeof(value)=="number"){
                writer.uint32(/* id 2, wireType 0 =*/16).int32(value);
                continue
            }
            if(typeof(value)=="string"){
                // writer.uint32(/* id 2, wireType 0 =*/16).int32(value);
                continue
            }
            //数组，map

            //自定义类型
            let codec = ProtobufProxy.codecMap.get(typeof(value))
            if (msg[key] != null && Object.hasOwnProperty.call(msg, key)){
                codec.encode(msg[key],writer.uint32(18).fork());
            }

        }

       //====================属性序列化_End======================
        return writer.finish()
    }
}

function ProtobufClass(type:new (...args: any[]) => any){
    //创建对于的解码编码器
    ProtobufProxy.create(type)
    // ProtobufClass.prototype["protos"] = ProtobufClass.prototype["protos"] || {} as {[typeName:string]:new (...args: any[]) => any}
    // let defines = ProtobufClass.prototype["protos"]
    // defines[type.name] = type
    return type
}

///////////////测试代码////////////////

//===============协议对象_Start==================
@ProtobufClass
export class RewardData{
    rewards:number[]
}
@ProtobufClass
export class C2G_EquipUpLevel{
    level:number;
    rewardData?:RewardData;
}
//===============协议对象_End==================

//eval只能执行js
class C2G_EquipUpLevel$$ProtoBufClass implements Codec<C2G_EquipUpLevel>{
    encode(msg: C2G_EquipUpLevel,writer?:protobuf.Writer): Uint8Array {
        if(!writer){
            writer = protobuf.Writer.create()
        }
        //===================属性序列化_Start=======================
        //基本类型 number string 
        //复杂类型 [] map set
        //自定义类型

        writer.uint32(/* id 2, wireType 0 =*/16).int32(msg.level);
        let codec = ProtobufProxy.codecMap.get("RewardData")
        if (msg.rewardData != null && Object.hasOwnProperty.call(msg, "rewardData"))
            codec.encode(msg.rewardData,writer.uint32(18).fork());
       //====================属性序列化_End======================
        return writer.finish()
    }
    decode(reader:any,length?:number): C2G_EquipUpLevel {
        if (!(reader instanceof protobuf.Reader))
            reader = protobuf.Reader.create(reader);
        let end = length === undefined ? reader.len : reader.pos + length
        let message = new C2G_EquipUpLevel();
        while (reader.pos < end) {
            let tag = reader.uint32();
            switch (tag >>> 3) {
            case 1: {
                    message.level = reader.int32();
                    break;
                }
            case 2: {
                    message.rewardData = ProtobufProxy.codecMap.get("RewardData").decode(reader, reader.uint32());
                    break;
                }
            default:
                reader.skipType(tag & 7);
                break;
            }
        }
        //require字段检查
        if (!message.hasOwnProperty("code"))
            throw new protobuf.util.ProtocolError("missing required 'code'", { instance: message });
        return message;
    }
    
}
// let equipLevelReq:C2G_EquipUpLevel = ProtobufProxy.decode(null)
// let equipUpLevelCodec = new C2G_EquipUpLevel$$ProtoBufClass()
// ProtobufProxy.codecMap.set("C2G_EquipUpLevel",equipUpLevelCodec)
// let test = ()=>{
//     let codec = ProtobufProxy.create(C2G_EquipUpLevel)
    
// }